﻿using System;
using System.Threading;
using S7PlcDataCollector.Models;
using S7PlcDataCollector.Service.Tools;
using S7PlcWrapper;

namespace S7PlcDataCollector.Service.PlcLink
{
    internal class PlcLinkHelper
    {
        private readonly S7PlcEntity _plcEntity;
        private readonly S7PlcHelper _plcHelper;
        private readonly IPlcLinkObserver _plcLinkObserver;
        private readonly CancellationTokenSource _tokenSource;

        #region 连接状态

        private PlcLinkState _linkState = PlcLinkState.Linking;
        private readonly object _linkStateLockHelper = new object();

        public PlcLinkState LinkState
        {
            get
            {
                PlcLinkState linkState;
                lock (_linkStateLockHelper)
                {
                    linkState = _linkState;
                }

                return linkState;
            }
            set
            {
                lock (_linkStateLockHelper)
                {
                    _linkState = value;
                }
            }
        }

        #endregion

        #region 线程

        private Thread _threadWorker;
        private bool _threadWorking;
        private readonly object _threadWorkingLockHelper = new object();

        private bool IsThreadWorking
        {
            get
            {
                bool ret;
                lock (_threadWorkingLockHelper)
                {
                    ret = _threadWorking;
                }

                return ret;
            }
            set
            {
                lock (_threadWorkingLockHelper)
                {
                    _threadWorking = value;
                }
            }
        }

        #endregion

        public PlcLinkHelper(S7PlcEntity plcEntity, S7PlcHelper plcHelper, IPlcLinkObserver plcLinkObserver)
        {
            _plcEntity = plcEntity;
            _plcHelper = plcHelper;
            _plcLinkObserver = plcLinkObserver;
            _tokenSource = new CancellationTokenSource();
        }

        public void Start()
        {
            IsThreadWorking = true;
            _threadWorker = new Thread(DoWork)
            {
                IsBackground = true
            };
            _threadWorker.Start();
        }

        public void Stop()
        {
            IsThreadWorking = false;
            _tokenSource.Cancel(false);
            if (_threadWorker != null)
            {
                _threadWorker.Join();
                _threadWorker = null;
            }
        }

        /// <summary>
        /// 线程执行方法
        /// </summary>
        private void DoWork()
        {
            while (IsThreadWorking)
            {
                switch (LinkState)
                {
                    case PlcLinkState.Linking:
                    case PlcLinkState.ReLinking:
                        LinkPlc();
                        break;
                    case PlcLinkState.Linked:
                        CheckPlc();
                        break;
                }

                //防止陷入死循环
                Thread.Sleep(_plcHelper.IsConnected ? 1000 : 1);
            }
        }

        private void LinkPlc()
        {
            //通知连接状态
            _plcLinkObserver.LinkStateChange(_plcEntity, LinkState);

            try
            {
                //连接不上的情况下大概需要20秒的时间
                _plcHelper.OpenAsync(_tokenSource.Token).GetAwaiter().GetResult();
            }
            catch (Exception e)
            {
                LogHelper.AddErrorLog(e.Message);
            }

            if (_plcHelper.IsConnected)
            {
                LinkState = PlcLinkState.Linked;
                _plcLinkObserver.LinkStateChange(_plcEntity, LinkState);
            }

            //_plcHelper.OpenAsync(_tokenSource.Token).GetAwaiter().OnCompleted(() =>
            //{
            //    if (_plcHelper.IsConnected)
            //    {
            //        LinkState = PlcLinkState.Linked;
            //        IsLinking = false;

            //        //通知连接状态
            //        _plcLinkObserver.LinkStateChange(_plcEntity, LinkState);
            //    }
            //});
        }

        private void CheckPlc()
        {
            //判断PLC是否在线
            if (!_plcHelper.IsConnected || !_plcHelper.IsOnline)
            {
                LinkState = PlcLinkState.ReLinking;
                LinkPlc();
            }
        }
    }
}
